// import com.alibaba.druid.DbType_ptr;
// import com.alibaba.druid.FastsqlException;
// import com.alibaba.druid.sql.SQLUtils;
// import com.alibaba.druid.sql.ast.SQLExpr_ptr;
// import com.alibaba.druid.sql.ast.SQLObject_ptr;
// import com.alibaba.druid.sql.ast.expr.*;
// import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
// import com.alibaba.druid.sql.ast.statement.SQLSelect;
// import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
// import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
// import com.alibaba.druid.sql.dialect.db2.visitor.DB2EvalVisitor;
// import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlEvalVisitorImpl;
// import com.alibaba.druid.sql.dialect.oracle.visitor.OracleEvalVisitor;
// import com.alibaba.druid.sql.dialect.postgresql.visitor.PGEvalVisitor;
// import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerEvalVisitor;
// import com.alibaba.druid.sql.visitor.functions.*;
// import com.alibaba.druid.util.HexBin;
// import com.alibaba.druid.util.Utils;
// import com.alibaba.druid.wall.spi.WallVisitorUtils;
// import com.alibaba.druid.wall.spi.WallVisitorUtils.WallConditionContext;

// import java.math.BigDecimal;
// import java.math.long long;
// import java.text.ParseException;
// import java.text.SimpleDateFormat;
// import java.util.*;
// import java.util.regex.Pattern;

// import static com.alibaba.druid.sql.visitor.SQLEvalVisitor* .*;
#include "SQLEvalVisitorUtils.h"
#include <limits.h>
#include <cmath>
#include <ctime>
#include <regex>
#include <cstdlib>
#include <climits>
#include <cfloat>
#include "SQLEvalVisitor.h"
#include "SQLEvalVisitorImpl.h"
#include "functions/Ascii.h"
#include "functions/Bin.h"
#include "functions/BitLength.h"
#include "functions/Char.h"
#include "functions/Concat.h"
#include "functions/DateAdd.h"
#include "functions/Elt.h"
#include "functions/Greatest.h"
#include "functions/Hex.h"
#include "functions/If.h"
#include "functions/Insert.h"
#include "functions/Instr.h"
#include "functions/Isnull.h"
#include "functions/Lcase.h"
#include "functions/Least.h"
#include "functions/Left.h"
#include "functions/Length.h"
#include "functions/Locate.h"
#include "functions/Lpad.h"
#include "functions/Ltrim.h"
#include "functions/Nil.h"
#include "functions/Now.h"
#include "functions/OneParamFunctions.h"
#include "functions/Reverse.h"
#include "functions/Right.h"
#include "functions/Substring.h"
#include "functions/ToChar.h"
#include "functions/ToDate.h"
#include "functions/Trim.h"
#include "functions/Ucase.h"
#include "functions/Unhex.h"
#include "../SQLUtils.h"
#include "../ast/expr/SQLNumericLiteralExpr.h"
#include "../ast/expr/SQLValuableExpr.h"
#include "../ast/expr/SQLHexExpr.h"
#include "../ast/expr/SQLCharExpr.h"
#include "../ast/expr/SQLBinaryExpr.h"
#include "../ast/expr/SQLQueryExpr.h"
#include "../ast/expr/SQLBetweenExpr.h"
#include "../ast/expr/SQLNullExpr.h"
#include "../ast/expr/SQLCaseExpr.h"
#include "../ast/expr/SQLInListExpr.h"
#include "../ast/expr/SQLUnaryExpr.h"
#include "../ast/expr/SQLUnaryOperator.h"
#include "../ast/expr/SQLBinaryOpExpr.h"
#include "../ast/expr/SQLVariantRefExpr.h"
#include "../../utils/instanceof.h"
#include "../../utils/StringUtils.h"
#include "../../utils/HexBin.h"
#include "../../utils/Utils.h"
#include "../../utils/TimeUtils.h"
#include "../../Exception/FastsqlException.h"
#include "../../Exception/IllegalArgumentException.h"
#include "../dialect/mysql/visitor/MySqlEvalVisitorImpl.h"
#include "../../wall/spi/WallVisitorUtils.h"

#define PI std::acos(-1)

std::map<std::string, SQLFunction *> SQLEvalVisitorUtils::functions;

bool SQLEvalVisitorUtils::__init = SQLEvalVisitorUtils::init();
bool SQLEvalVisitorUtils::init()
{
  SQLEvalVisitorUtils::registerBaseFunctions();
}

Object_ptr SQLEvalVisitorUtils::evalExpr(DbType_ptr dbType, string_ptr expr, Object_ptr parameters)
{
  SQLExpr_ptr sqlExpr = SQLUtils::toSQLExpr(expr, dbType);
  return eval(dbType, sqlExpr, parameters);
}

Object_ptr SQLEvalVisitorUtils::evalExpr(DbType_ptr dbType, string_ptr expr, Object_list_ptr parameters)
{
  SQLExpr_ptr sqlExpr = SQLUtils::toSQLExpr(expr);
  return eval(dbType, sqlExpr, parameters);
}

Object_ptr SQLEvalVisitorUtils::eval(DbType_ptr dbType, SQLObject_ptr sqlObject, Object_ptr parameters)
{
  Object_list_ptr tmp = std::make_shared<std::list<Object_ptr>>();
  tmp->push_back(parameters);
  Object_ptr value = eval(dbType, sqlObject, tmp);

  if (value == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    value = nullptr;
  }

  return value;
}

Object_ptr SQLEvalVisitorUtils::getValue(SQLObject_ptr sqlObject)
{
  if (instanceof <SQLObject, SQLNumericLiteralExpr>(sqlObject))
  {
    // return (std::dynamic_pointer_cast<SQLNumericLiteralExpr>(sqlObject) )->getNumber();
    return std::dynamic_pointer_cast<SQLNumericLiteralExpr>(sqlObject);
  }

  return sqlObject->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());
}

Object_ptr SQLEvalVisitorUtils::eval(DbType_ptr dbType, SQLObject_ptr sqlObject, Object_list_ptr parameters)
{
  return eval(dbType, sqlObject, parameters, true);
}

Object_ptr SQLEvalVisitorUtils::eval(DbType_ptr dbType, SQLObject_ptr sqlObject, Object_list_ptr parameters, bool throwError)
{
  SQLEvalVisitor_ptr visitor = createEvalVisitor(dbType);
  visitor->setParameters(parameters);

  Object_ptr value;
  if (instanceof <SQLObject, SQLValuableExpr>(sqlObject))
  {
    value = (std::dynamic_pointer_cast<SQLValuableExpr>(sqlObject))->getValue();
  }
  else
  {
    sqlObject->accept(visitor);

    value = getValue(sqlObject);

    if (value == nullptr)
    {
      if (throwError && !sqlObject->containsAttribute(SQLEvalVisitor::EVAL_VALUE))
      {
        std::string tmp = "eval error : ";
        tmp += SQLUtils::toSQLString(sqlObject, dbType)->c_str();
        throw new FastsqlException(make_string_ptr(tmp));
      }
    }
  }

  return value;
}

SQLEvalVisitor_ptr SQLEvalVisitorUtils::createEvalVisitor(DbType_ptr dbType)
{
  if (dbType == nullptr)
  {
    dbType = DbType_ptr(new DbType(&DbType::other));
  }

  if (dbType->name->c_str() == DbType::mysql.name->c_str() ||
      dbType->name->c_str() == DbType::mariadb.name->c_str() ||
      dbType->name->c_str() == DbType::tidb.name->c_str() ||
      dbType->name->c_str() == DbType::h2.name->c_str())
  {
    return MySqlEvalVisitorImpl_ptr(new MySqlEvalVisitorImpl());
  }
  else if (dbType->name->c_str() == DbType::oracle.name->c_str())
  {
    // return OracleEvalVisitor_ptr(new OracleEvalVisitor());
  }
  else if (dbType->name->c_str() == DbType::postgresql.name->c_str() ||
           dbType->name->c_str() == DbType::edb.name->c_str())
  {
    // return new PGEvalVisitor();
  }
  else if (dbType->name->c_str() == DbType::sqlserver.name->c_str() ||
           dbType->name->c_str() == DbType::jtds.name->c_str())
  {
    // return SQLServerEvalVisitor_ptr(new SQLServerEvalVisitor());
  }
  else if (dbType->name->c_str() == DbType::db2.name->c_str())
  {
    // return new DB2EvalVisitor();
  }
  else
  {
    return SQLEvalVisitorImpl_ptr(new SQLEvalVisitorImpl());
  }
}

void SQLEvalVisitorUtils::registerBaseFunctions()
{
  functions.insert(std::make_pair("now", Now::instance()));
  functions.insert(std::make_pair("concat", Concat::instance()));
  functions.insert(std::make_pair("concat_ws", Concat::instance()));
  functions.insert(std::make_pair("ascii", Ascii::instance()));
  functions.insert(std::make_pair("bin", Bin::instance()));
  functions.insert(std::make_pair("bit_length", BitLength::instance()));
  functions.insert(std::make_pair("insert", Insert::instance()));
  functions.insert(std::make_pair("instr", Instr::instance()));
  functions.insert(std::make_pair("char", SQLChar::instance()));
  functions.insert(std::make_pair("elt", Elt::instance()));
  functions.insert(std::make_pair("left", Left::instance()));
  functions.insert(std::make_pair("locate", Locate::instance()));
  functions.insert(std::make_pair("lpad", Lpad::instance()));
  functions.insert(std::make_pair("ltrim", Ltrim::instance()));
  functions.insert(std::make_pair("mid", Substring::instance()));
  functions.insert(std::make_pair("substr", Substring::instance()));
  functions.insert(std::make_pair("substring", Substring::instance()));
  functions.insert(std::make_pair("right", Right::instance()));
  functions.insert(std::make_pair("reverse", Reverse::instance()));
  functions.insert(std::make_pair("len", Length::instance()));
  functions.insert(std::make_pair("length", Length::instance()));
  functions.insert(std::make_pair("char_length", Length::instance()));
  functions.insert(std::make_pair("character_length", Length::instance()));
  functions.insert(std::make_pair("trim", Trim::instance()));
  functions.insert(std::make_pair("ucase", Ucase::instance()));
  functions.insert(std::make_pair("upper", Ucase::instance()));
  functions.insert(std::make_pair("lcase", Lcase::instance()));
  functions.insert(std::make_pair("lower", Lcase::instance()));
  functions.insert(std::make_pair("hex", Hex::instance()));
  functions.insert(std::make_pair("unhex", Unhex::instance()));
  functions.insert(std::make_pair("greatest", Greatest::instance()));
  functions.insert(std::make_pair("least", Least::instance()));
  functions.insert(std::make_pair("isnull", Isnull::instance()));
  functions.insert(std::make_pair("if", If::instance()));
  functions.insert(std::make_pair("to_date", ToDate::instance()));
  functions.insert(std::make_pair("to_char", ToChar::instance()));
  functions.insert(std::make_pair("dateadd", DateAdd::instance()));
  functions.insert(std::make_pair("md5", OneParamFunctions::instance()));
  functions.insert(std::make_pair("bit_count", OneParamFunctions::instance()));
  functions.insert(std::make_pair("soundex", OneParamFunctions::instance()));
  functions.insert(std::make_pair("space", OneParamFunctions::instance()));
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLMethodInvokeExpr_ptr x)
{
  string_ptr methodName = StringUtils::toLower(x->getMethodName());

  SQLFunction *function = visitor->getFunction(methodName->c_str());

  if (function == nullptr)
  {
    auto tmp = functions.find(methodName->c_str());
    if (tmp != functions.end())
    {
      function = tmp->second;
    }
  }

  if (function != nullptr)
  {
    Object_ptr result = function->eval(visitor, x.get());

    if (result != SQLEvalVisitor::EVAL_ERROR && result != nullptr)
    {
      x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), result);
    }
    return false;
  }

  if ("mod" == methodName->c_str())
  {
    if (x->getArguments()->size() != 2)
    {
      return false;
    }

    auto it_getArguments = x->getArguments()->begin();
    std::advance(it_getArguments, 0);
    SQLExpr_ptr param0 = *it_getArguments;
    std::advance(it_getArguments, 1);
    SQLExpr_ptr param1 = *it_getArguments;
    param0->accept(SQLEvalVisitor_ptr(visitor));
    param1->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr param0Value = nullptr;
    auto tmp1 = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp1 != param0->getAttributes()->end())
    {
      param0Value = tmp1->second;
    }
    Object_ptr param1Value = nullptr;
    auto tmp2 = param1->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp2 != param1->getAttributes()->end())
    {
      param1Value = tmp2->second;
    }
    if (param0Value == nullptr || param1Value == nullptr)
    {
      return false;
    }

    long intValue0 = castToLong(param0Value);
    long intValue1 = castToLong(param1Value);

    long result = intValue0 % intValue1;
    if (result >= INT_MIN && result <= INT_MAX)
    {
      int intResult = (int)result;
      x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(intResult)));
    }
    else
    {
      x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    }
  }
  else if ("abs" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }
    if (paramValue == nullptr)
    {
      return false;
    }

    Object_ptr result;
    if (paramValue->getType() == Object::ParamType::INT)
    {
      result = Object_ptr(new Object(std::abs(paramValue->getInt())));
    }
    else if (paramValue->getType() == Object::ParamType::LONG)
    {
      result = Object_ptr(new Object(std::abs(paramValue->getInt())));
    }
    else
    {
      result = Object_ptr(new Object(std::fabs(castToDecimal(paramValue))));
    }

    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), result);
  }
  else if ("acos" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }

    if (paramValue == nullptr)
    {
      return false;
    }

    double doubleValue = castToDouble(paramValue);
    double result = std::acos(doubleValue);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("asin" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }
    if (paramValue == nullptr)
    {
      return false;
    }

    double doubleValue = castToDouble(paramValue);
    double result = std::asin(doubleValue);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("atan" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }
    if (paramValue == nullptr)
    {
      return false;
    }

    double doubleValue = castToDouble(paramValue);
    double result = std::atan(doubleValue);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("atan2" == methodName->c_str())
  {
    if (x->getArguments()->size() != 2)
    {
      return false;
    }

    auto it = x->getArguments()->begin();
    SQLExpr_ptr param0 = *it;
    std::advance(it, 1);
    SQLExpr_ptr param1 = *it;
    param0->accept(SQLEvalVisitor_ptr(visitor));
    param1->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr param0Value = nullptr;
    auto tmp1 = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp1 != param0->getAttributes()->end())
    {
      param0Value = tmp1->second;
    }
    Object_ptr param1Value = nullptr;
    auto tmp2 = param1->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp2 != param1->getAttributes()->end())
    {
      param1Value = tmp2->second;
    }

    if (param0Value == nullptr || param1Value == nullptr)
    {
      return false;
    }

    double doubleValue0 = castToDouble(param0Value);
    double doubleValue1 = castToDouble(param1Value);
    double result = std::atan2(doubleValue0, doubleValue1);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("ceil" == methodName->c_str() || "ceiling" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }
    if (paramValue == nullptr)
    {
      return false;
    }

    double doubleValue = castToDouble(paramValue);
    // if (double.isNaN(doubleValue)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    int result = (int)std::ceil(doubleValue);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("cos" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }
    if (paramValue == nullptr)
    {
      return false;
    }

    double doubleValue = castToDouble(paramValue);
    double result = std::cos(doubleValue);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("sin" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }
    if (paramValue == nullptr)
    {
      return false;
    }

    double doubleValue = castToDouble(paramValue);
    double result = std::sin(doubleValue);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("log" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }
    if (paramValue == nullptr)
    {
      return false;
    }

    double doubleValue = castToDouble(paramValue);
    double result = std::log(doubleValue);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("log10" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }
    if (paramValue == nullptr)
    {
      return false;
    }

    double doubleValue = castToDouble(paramValue);
    double result = std::log10(doubleValue);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("tan" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }
    if (paramValue == nullptr)
    {
      return false;
    }

    double doubleValue = castToDouble(paramValue);
    double result = std::tan(doubleValue);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("sqrt" == methodName->c_str())
  {
    if (x->getArguments()->size() != 1)
    {
      return false;
    }

    SQLExpr_ptr param0 = *(x->getArguments()->begin());
    param0->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr paramValue = nullptr;
    auto tmp = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp != param0->getAttributes()->end())
    {
      paramValue = tmp->second;
    }
    if (paramValue == nullptr)
    {
      return false;
    }

    double doubleValue = castToDouble(paramValue);
    double result = std::sqrt(doubleValue);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("power" == methodName->c_str() || "pow" == methodName->c_str())
  {
    if (x->getArguments()->size() != 2)
    {
      return false;
    }

    auto it = x->getArguments()->begin();
    SQLExpr_ptr param0 = *it;
    std::advance(it, 1);
    SQLExpr_ptr param1 = *it;
    param0->accept(SQLEvalVisitor_ptr(visitor));
    param1->accept(SQLEvalVisitor_ptr(visitor));

    Object_ptr param0Value = nullptr;
    auto tmp1 = param0->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp1 != param0->getAttributes()->end())
    {
      param0Value = tmp1->second;
    }
    Object_ptr param1Value = nullptr;
    auto tmp2 = param1->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (tmp2 != param1->getAttributes()->end())
    {
      param1Value = tmp2->second;
    }
    if (param0Value == nullptr || param1Value == nullptr)
    {
      return false;
    }

    double doubleValue0 = castToDouble(param0Value);
    double doubleValue1 = castToDouble(param1Value);
    double result = std::pow(doubleValue0, doubleValue1);

    // if (double.isNaN(result)) {
    //     x->putAttribute(EVAL_VALUE, nullptr);
    // } else {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
    // }
  }
  else if ("pi" == methodName->c_str())
  {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(PI)));
  }
  else if ("rand" == methodName->c_str())
  {
    std::srand(std::time(nullptr));
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(std::rand())));
  }
  else if ("chr" == methodName->c_str() && x->getArguments()->size() == 1)
  {
    SQLExpr_ptr first = *(x->getArguments()->begin());
    Object_ptr firstResult = getValue(first);
    if (firstResult->getType() == Object::ParamType::DOUBLE)
    {
      int intValue = (int)firstResult->getDouble();
      char ch = (char)intValue;
      x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(std::to_string(ch))));
    }
  }
  else if ("current_user" == methodName->c_str())
  {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object("CURRENT_USER")));
  }
  return false;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLCharExpr_ptr x)
{
  x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(x->getText()->c_str())));
  return true;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLHexExpr_ptr x)
{
  string_ptr hex = x->getHex();
  const char *bytes = HexBin::decode(hex->c_str());
  if (bytes == nullptr)
  {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), SQLEvalVisitor::EVAL_ERROR);
  }
  else
  {
    string_ptr val = make_string_ptr(bytes);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(val->c_str())));
  }
  return true;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLBinaryExpr_ptr x)
{
  string_ptr text = x->getText();

  long words[text->length() / 64 + 1];
  for (int i = text->length() - 1; i >= 0; --i)
  {
    char ch = text->at(i);
    if (ch == '1')
    {
      int wordIndex = i >> 6;
      words[wordIndex] |= (1L << (text->length() - 1 - i));
    }
  }

  Object_ptr val;

  if (sizeof(words) == 1)
  {
    val = Object_ptr(new Object(words[0]));
  }
  else
  {
    char bytes[sizeof(words) * 8];

    for (int i = 0; i < sizeof(words); ++i)
    {
      Utils::putLong(bytes, (sizeof(words) - 1 - i) * 8, words[i]);
    }

    val = Object_ptr(new Object((long long)bytes));
  }

  x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), val);

  return false;
}

SQLExpr_ptr SQLEvalVisitorUtils::unwrap(SQLExpr_ptr expr)
{
  if (expr == nullptr)
  {
    return nullptr;
  }

  if (instanceof <SQLExpr, SQLQueryExpr>(expr))
  {
    SQLSelect_ptr select = (std::dynamic_pointer_cast<SQLQueryExpr>(expr))->getSubQuery();
    if (select == nullptr)
    {
      return nullptr;
    }
    if (instanceof <SQLSelectQuery, SQLSelectQueryBlock>(select->getQuery()))
    {
      SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(select->getQuery());
      if (queryBlock->getFrom() == nullptr)
      {
        if (queryBlock->getSelectList()->size() == 1)
        {
          return (*(queryBlock->getSelectList()->begin()))->getExpr();
        }
      }
    }
  }

  return expr;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLBetweenExpr_ptr x)
{
  SQLExpr_ptr testExpr = unwrap(x->getTestExpr());
  testExpr->accept(SQLEvalVisitor_ptr(visitor));

  if (testExpr->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str()) == 0)
  {
    return false;
  }

  Object_ptr value = testExpr->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());

  SQLExpr_ptr beginExpr = unwrap(x->getBeginExpr());
  beginExpr->accept(SQLEvalVisitor_ptr(visitor));
  if (beginExpr->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str()) == 0)
  {
    return false;
  }

  Object_ptr begin = beginExpr->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());

  if (lt(value, begin))
  {
    x->getAttributes()->insert(std::make_pair(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(x->isNot() ? true : false))));
    return false;
  }

  SQLExpr_ptr endExpr = unwrap(x->getEndExpr());
  endExpr->accept(SQLEvalVisitor_ptr(visitor));
  if (endExpr->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str()) == 0)
  {
    return false;
  }

  Object_ptr end = endExpr->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());

  if (gt(value, end))
  {
    x->getAttributes()->insert(std::make_pair(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(x->isNot() ? true : false))));
    return false;
  }

  x->getAttributes()->insert(std::make_pair(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(x->isNot() ? true : false))));
  return false;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLNullExpr_ptr x)
{
  x->getAttributes()->insert(std::make_pair(SQLEvalVisitor::EVAL_VALUE->c_str(), SQLEvalVisitor::EVAL_VALUE_NULL));
  return false;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLCaseExpr_ptr x)
{
  Object_ptr value;
  if (x->getValueExpr() != nullptr)
  {
    x->getValueExpr()->accept(SQLEvalVisitor_ptr(visitor));

    if (x->getValueExpr()->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str()) == 0)
    {
      return false;
    }

    value = x->getValueExpr()->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());
  }
  else
  {
    value = nullptr;
  }

  for (SQLCaseExpr_Item_ptr item : *x->getItems())
  {
    item->getConditionExpr()->accept(SQLEvalVisitor_ptr(visitor));

    if (item->getConditionExpr()->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str()) == 0)
    {
      return false;
    }

    Object_ptr conditionValue = item->getConditionExpr()->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());

    if ((x->getValueExpr() != nullptr &&
         eq(value, conditionValue)) ||
        (x->getValueExpr() == nullptr &&
         conditionValue->getType() == Object::ParamType::BOOL &&
         (bool)conditionValue->getBool() == true))
    {
      item->getValueExpr()->accept(SQLEvalVisitor_ptr(visitor));

      if (item->getValueExpr()->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str()) == 0)
      {
        x->getAttributes()->insert(std::make_pair(SQLEvalVisitor::EVAL_VALUE->c_str(), item->getValueExpr()->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str())));
      }

      return false;
    }
  }

  if (x->getElseExpr() != nullptr)
  {
    x->getElseExpr()->accept(SQLEvalVisitor_ptr(visitor));

    if (x->getElseExpr()->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str()) != 0)
    {
      x->getAttributes()->insert(std::make_pair(SQLEvalVisitor::EVAL_VALUE->c_str(), x->getElseExpr()->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str())));
    }
  }

  return false;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLInListExpr_ptr x)
{
  SQLExpr_ptr valueExpr = x->getExpr();
  valueExpr->accept(SQLEvalVisitor_ptr(visitor));
  if (valueExpr->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str()) == 0)
  {
    return false;
  }
  Object_ptr value = valueExpr->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());

  for (SQLExpr_ptr item : *x->getTargetList())
  {
    item->accept(SQLEvalVisitor_ptr(visitor));
    if (item->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str()) == 0)
    {
      return false;
    }
    Object_ptr itemValue = item->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (eq(value, itemValue))
    {
      x->getAttributes()->insert(std::make_pair(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(x->isNot() ? false : true))));
      return false;
    }
  }

  x->getAttributes()->insert(std::make_pair(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(x->isNot() ? false : true))));
  return false;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLQueryExpr_ptr x)
{
  if (WallVisitorUtils::isSimpleCountTableSource(nullptr, (std::dynamic_pointer_cast<SQLQueryExpr>(x))->getSubQuery()))
  {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(1)));
    return false;
  }

  if (instanceof <SQLSelectQuery, SQLSelectQueryBlock>(x->getSubQuery()->getQuery()))
  {
    SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(x->getSubQuery()->getQuery());

    bool nullFrom = false;
    if (queryBlock->getFrom() == nullptr)
    {
      nullFrom = true;
    }
    else if (instanceof <SQLTableSource, SQLExprTableSource>(queryBlock->getFrom()))
    {
      SQLExpr_ptr expr = (std::dynamic_pointer_cast<SQLExprTableSource>(queryBlock->getFrom()))->getExpr();
      if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
      {
        if (StringUtils::equalsIgnoreCase(make_string_ptr("dual"), ((std::dynamic_pointer_cast<SQLIdentifierExpr>(expr))->getName())))
        {
          nullFrom = true;
        }
      }
    }

    if (nullFrom)
    {
      Object_list_ptr row = std::make_shared<std::list<Object_ptr>>();
      auto it_getSelectList = queryBlock->getSelectList()->begin();
      for (int i = 0; i < queryBlock->getSelectList()->size(); ++i)
      {
        std::advance(it_getSelectList, i);
        SQLSelectItem_ptr item = *it_getSelectList;
        item->getExpr()->accept(SQLEvalVisitor_ptr(visitor));
        Object_ptr cell = item->getExpr()->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());
        row->push_back(cell);
      }
      std::shared_ptr<std::list<Object_list_ptr>> rows = std::make_shared<std::list<Object_list_ptr>>();
      rows->push_back(row);

      Object_ptr result = Object_ptr(new Object(rows));
      queryBlock->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), result);
      x->getSubQuery()->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), result);
      x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), result);

      return false;
    }
  }

  return false;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLUnaryExpr_ptr x)
{
  WallVisitorUtils_WallConditionContext_ptr wallConditionContext = WallVisitorUtils::getWallConditionContext();
  if (x->getOperator()->name->c_str() == SQLUnaryOperator::Compl.name->c_str() && wallConditionContext != nullptr)
  {
    wallConditionContext->setBitwise(true);
  }

  x->getExpr()->accept(SQLEvalVisitor_ptr(visitor));

  Object_ptr val = x->getExpr()->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());
  if (val == SQLEvalVisitor::EVAL_ERROR)
  {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), SQLEvalVisitor::EVAL_ERROR);
    return false;
  }

  if (val == nullptr)
  {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), SQLEvalVisitor::EVAL_VALUE_NULL);
    return false;
  }

  if (x->getOperator()->name->c_str() == SQLUnaryOperator::BINARY.name->c_str() ||
      x->getOperator()->name->c_str() == SQLUnaryOperator::RAW.name->c_str())
  {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), val);
  }
  else if (x->getOperator()->name->c_str() == SQLUnaryOperator::NOT.name->c_str() ||
           x->getOperator()->name->c_str() == SQLUnaryOperator::Not.name->c_str())
  {
    BOOL_ptr booleanVal = castToBoolean(val);
    if (*booleanVal != BOOL::NIL)
    {
      x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(!(*booleanVal == BOOL::TRUE))));
    }
  }
  else if (x->getOperator()->name->c_str() == SQLUnaryOperator::Plus.name->c_str())
  {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), val);
  }
  else if (x->getOperator()->name->c_str() == SQLUnaryOperator::Negative.name->c_str())
  {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), multi(val, Object_ptr(new Object(-1))));
  }
  else if (x->getOperator()->name->c_str() == SQLUnaryOperator::Compl.name->c_str())
  {
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(~castToInteger(val))));
  }

  return false;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLBinaryOpExpr_ptr x)
{
  SQLExpr_ptr left = unwrap(x->getLeft());
  SQLExpr_ptr right = unwrap(x->getRight());

  // WallConditionContext old = wallConditionContextLocal.get();

  left->accept(SQLEvalVisitor_ptr(visitor));
  right->accept(SQLEvalVisitor_ptr(visitor));

  WallVisitorUtils_WallConditionContext_ptr wallConditionContext = WallVisitorUtils::getWallConditionContext();
  if (x->getOperator()->name->c_str() == SQLBinaryOperator::BooleanOr.name->c_str())
  {
    if (wallConditionContext != nullptr)
    {
      if (left->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str())->getBool() == true ||
          right->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str())->getBool() == true)
      {
        wallConditionContext->setPartAlwayTrue(true);
      }
    }
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::BooleanAnd.name->c_str())
  {
    if (wallConditionContext != nullptr)
    {
      if (left->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str())->getBool() == false ||
          right->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str())->getBool() == false)
      {
        wallConditionContext->setPartAlwayFalse(true);
      }
    }
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::BooleanXor.name->c_str())
  {
    if (wallConditionContext != nullptr)
    {
      wallConditionContext->setXor(true);
    }
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::BitwiseAnd.name->c_str()    //
           || x->getOperator()->name->c_str() == SQLBinaryOperator::BitwiseNot.name->c_str() //
           || x->getOperator()->name->c_str() == SQLBinaryOperator::BitwiseOr.name->c_str()  //
           || x->getOperator()->name->c_str() == SQLBinaryOperator::BitwiseXor.name->c_str())
  {
    if (wallConditionContext != nullptr)
    {
      wallConditionContext->setBitwise(true);
    }
  }

  Object_ptr leftValue = left->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());
  Object_ptr rightValue = nullptr;
  auto it = right->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
  if (it != right->getAttributes()->end())
  {
    rightValue = it->second;
  }

  if (x->getOperator()->name->c_str() == SQLBinaryOperator::Like.name->c_str())
  {
    if (isAlwayTrueLikePattern(x->getRight()))
    {
      x->putAttribute(WallVisitorUtils::HAS_TRUE_LIKE, Object_ptr(new Object(true)));
      x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(true)));
      return false;
    }
  }

  if (x->getOperator()->name->c_str() == SQLBinaryOperator::NotLike.name->c_str())
  {
    if (isAlwayTrueLikePattern(x->getRight()))
    {
      x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(false)));
      return false;
    }
  }

  bool leftHasValue = left->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str());
  bool rightHasValue = right->getAttributes()->count(SQLEvalVisitor::EVAL_VALUE->c_str());

  if ((!leftHasValue) && !rightHasValue)
  {
    SQLExpr_ptr leftEvalExpr = std::dynamic_pointer_cast<SQLExpr>(left->getAttribute(SQLEvalVisitor::EVAL_EXPR->c_str()));
    SQLExpr_ptr rightEvalExpr = std::dynamic_pointer_cast<SQLExpr>(right->getAttribute(SQLEvalVisitor::EVAL_EXPR->c_str()));

    if (leftEvalExpr != nullptr && leftEvalExpr->equals(rightEvalExpr))
    {

      if (x->getOperator()->name->c_str() == SQLBinaryOperator::Like.name->c_str() ||
          x->getOperator()->name->c_str() == SQLBinaryOperator::SoudsLike.name->c_str() ||
          x->getOperator()->name->c_str() == SQLBinaryOperator::Equality.name->c_str() ||
          x->getOperator()->name->c_str() == SQLBinaryOperator::GreaterThanOrEqual.name->c_str() ||
          x->getOperator()->name->c_str() == SQLBinaryOperator::LessThanOrEqual.name->c_str() ||
          x->getOperator()->name->c_str() == SQLBinaryOperator::NotLessThan.name->c_str() ||
          x->getOperator()->name->c_str() == SQLBinaryOperator::NotGreaterThan.name->c_str())
      {
        x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(true)));
        return false;
      }
      else if (x->getOperator()->name->c_str() == SQLBinaryOperator::NotEqual.name->c_str() ||
               x->getOperator()->name->c_str() == SQLBinaryOperator::LessThanOrGreater.name->c_str() ||
               x->getOperator()->name->c_str() == SQLBinaryOperator::NotLike.name->c_str() ||
               x->getOperator()->name->c_str() == SQLBinaryOperator::GreaterThan.name->c_str() ||
               x->getOperator()->name->c_str() == SQLBinaryOperator::LessThan.name->c_str())
      {
        x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(false)));
        return false;
      }
    }
  }

  if (!leftHasValue)
  {
    return false;
  }

  if (!rightHasValue)
  {
    return false;
  }

  if (wallConditionContext != nullptr)
  {
    wallConditionContext->setConstArithmetic(true);
  }

  leftValue = processValue(leftValue);
  rightValue = processValue(rightValue);

  if (leftValue == nullptr || rightValue == nullptr)
  {
    return false;
  }

  Object_ptr value = nullptr;

  if (x->getOperator()->name->c_str() == SQLBinaryOperator::Add.name->c_str())
  {
    value = add(leftValue, rightValue);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::Subtract.name->c_str())
  {
    value = sub(leftValue, rightValue);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::Multiply.name->c_str())
  {
    value = multi(leftValue, rightValue);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::Divide.name->c_str())
  {
    value = div(leftValue, rightValue);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::RightShift.name->c_str())
  {
    value = rightShift(leftValue, rightValue);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::BitwiseAnd.name->c_str())
  {
    value = bitAnd(leftValue, rightValue);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::BitwiseOr.name->c_str())
  {
    value = bitOr(leftValue, rightValue);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::GreaterThan.name->c_str())
  {
    value = Object_ptr(new Object(gt(leftValue, rightValue)));
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::GreaterThanOrEqual.name->c_str())
  {
    value = Object_ptr(new Object(gteq(leftValue, rightValue)));
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::LessThan.name->c_str())
  {
    value = Object_ptr(new Object(lt(leftValue, rightValue)));
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::LessThanOrEqual.name->c_str())
  {
    value = Object_ptr(new Object(lteq(leftValue, rightValue)));
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::Is.name->c_str())
  {
    if (rightValue == SQLEvalVisitor::EVAL_VALUE_NULL)
    {
      if (leftValue != nullptr)
      {
        value = Object_ptr(new Object((leftValue == SQLEvalVisitor::EVAL_VALUE_NULL)));
        x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
      }
    }
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::Equality.name->c_str())
  {
    value = Object_ptr(new Object(eq(leftValue, rightValue)));
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::NotEqual.name->c_str() ||
           x->getOperator()->name->c_str() == SQLBinaryOperator::LessThanOrGreater.name->c_str())
  {
    value = Object_ptr(new Object(!eq(leftValue, rightValue)));
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), value);
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::IsNot.name->c_str())
  {
    if (leftValue == SQLEvalVisitor::EVAL_VALUE_NULL)
    {
      x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(false)));
    }
    else if (leftValue != nullptr)
    {
      x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(true)));
    }
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::RegExp.name->c_str() ||
           x->getOperator()->name->c_str() == SQLBinaryOperator::RLike.name->c_str())
  {
    string_ptr pattern = castToString(rightValue);
    Object_ptr tmp = nullptr;
    auto it = left->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (it != left->getAttributes()->end())
    {
      tmp = it->second;
    }
    string_ptr input = castToString(tmp);
    // bool matchResult = Pattern.matches(pattern, input);
    std::regex reg(pattern->c_str());
    bool matchResult = std::regex_match(input->c_str(), reg);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(matchResult)));
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::NotRegExp.name->c_str() ||
           x->getOperator()->name->c_str() == SQLBinaryOperator::NotRLike.name->c_str())
  {
    string_ptr pattern = castToString(rightValue);
    Object_ptr tmp = nullptr;
    auto it = left->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (it != left->getAttributes()->end())
    {
      tmp = it->second;
    }
    string_ptr input = castToString(tmp);
    // bool matchResult = !Pattern.matches(pattern, input);
    std::regex reg(pattern->c_str());
    bool matchResult = !std::regex_match(input->c_str(), reg);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(matchResult)));
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::Like.name->c_str())
  {
    string_ptr pattern = castToString(rightValue);
    Object_ptr tmp = nullptr;
    auto it = left->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (it != left->getAttributes()->end())
    {
      tmp = it->second;
    }
    string_ptr input = castToString(tmp);
    bool matchResult = like(input, pattern);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(matchResult)));
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::NotLike.name->c_str())
  {
    string_ptr pattern = castToString(rightValue);
    Object_ptr tmp = nullptr;
    auto it = left->getAttributes()->find(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (it != left->getAttributes()->end())
    {
      tmp = it->second;
    }
    string_ptr input = castToString(tmp);
    bool matchResult = !like(input, pattern);
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(matchResult)));
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::Concat.name->c_str())
  {
    std::string result = leftValue->getString() + rightValue->getString();
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(result)));
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::BooleanAnd.name->c_str())
  {
    bool first = eq(leftValue, Object_ptr(new Object(true)));
    bool second = eq(rightValue, Object_ptr(new Object(true)));
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(first && second)));
  }
  else if (x->getOperator()->name->c_str() == SQLBinaryOperator::BooleanOr.name->c_str())
  {
    bool first = eq(leftValue, Object_ptr(new Object(true)));
    bool second = eq(rightValue, Object_ptr(new Object(true)));
    x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(first || second)));
  }

  return false;
}

// @SuppressWarnings("rawtypes")
Object_ptr SQLEvalVisitorUtils::processValue(Object_ptr value)
{
  if (value->getType() == Object::ParamType::LISTOBJ)
  {
    Object_list_ptr list = value->getLO();
    if (list->size() == 1)
    {
      return processValue((*(list->begin())));
    }
  }
  else if (value->getType() == Object::ParamType::LONG)
  {
    // return ((time_t) value).getTime();
    return value;
  }
  return value;
}

bool SQLEvalVisitorUtils::isAlwayTrueLikePattern(SQLExpr_ptr x)
{
  if (instanceof <SQLExpr, SQLCharExpr>(x))
  {
    string_ptr text = (std::dynamic_pointer_cast<SQLCharExpr>(x))->getText();

    if (text->length() > 0)
    {
      for (char ch : *text)
      {
        if (ch != '%')
        {
          return false;
        }
      }
      return true;
    }
  }
  return false;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLNumericLiteralExpr_ptr x)
{
  x->putAttribute(SQLEvalVisitor::EVAL_VALUE->c_str(), Object_ptr(new Object(x->getNumber())));
  return false;
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLVariantRefExpr_ptr x)
{
  if ("?" == x->getName()->c_str())
  {
    return false;
  }

  std::shared_ptr<std::map<std::__cxx11::string, Object_ptr>> attributes = x->getAttributes();

  int varIndex = x->getIndex();

  Object_list_ptr parameters = visitor->getParameters();
  if (varIndex != -1 && parameters != nullptr && parameters->size() > varIndex)
  {
    bool containsValue = attributes->count(SQLEvalVisitor::EVAL_VALUE->c_str());
    if (!containsValue)
    {
      auto it_parameters = parameters->begin();
      std::advance(it_parameters, varIndex);
      Object_ptr value = *it_parameters;
      if (value == nullptr)
      {
        value = SQLEvalVisitor::EVAL_VALUE_NULL;
      }
      attributes->insert(std::make_pair(SQLEvalVisitor::EVAL_VALUE->c_str(), value));
    }
  }

  return false;
}

BOOL_ptr SQLEvalVisitorUtils::castToBoolean(Object_ptr val)
{
  if (val == nullptr)
  {
    return BOOL::NIL;
  }

  if (val == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return nullptr;
  }

  if (val->getType() == Object::ParamType::BOOL)
  {
    return val->getBool() ? BOOL::TRUE : BOOL::FALSE;
  }

  if (val->getType() == Object::ParamType::DOUBLE)
  {
    return val->getDouble() > 0 ? BOOL::TRUE : BOOL::FALSE;
  }

  if (val->getType() == Object::ParamType::STRING)
  {
    if ("1" == val->getString() || StringUtils::iequals("true", val->getString()))
    {
      return BOOL::TRUE;
    }

    return BOOL::FALSE;
  }

  std::string tmp = val->getClass()->c_str();
  tmp += " not supported.";
  throw new IllegalArgumentException(make_string_ptr(tmp));
}

string_ptr SQLEvalVisitorUtils::castToString(Object_ptr val)
{
  Object_ptr value = val;

  if (value == nullptr)
  {
    return nullptr;
  }

  return make_string_ptr(value->getString());
}

char SQLEvalVisitorUtils::castToByte(Object_ptr val)
{
  if (val == nullptr)
  {
    return '\0';
  }

  if (val->getType() == Object::ParamType::CHAR)
  {
    return val->getC();
  }

  if (val->getType() == Object::ParamType::STRING)
  {
    return atoi(val->getString().c_str());
  }

  return val->getDouble();
}

short SQLEvalVisitorUtils::castToShort(Object_ptr val)
{
  if (val == nullptr || val == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return NULL;
  }

  if (val->getType() == Object::ParamType::SHORT)
  {
    return val->getShort();
  }

  if (val->getType() == Object::ParamType::STRING)
  {
    return atoi(val->getString().c_str());
  }

  // return ((double) val).shortValue();
  return val->getDouble();
}

// @SuppressWarnings("rawtypes")
int SQLEvalVisitorUtils::castToInteger(Object_ptr val)
{
  if (val == nullptr)
  {
    return NULL;
  }

  if (val->getType() == Object::ParamType::INT)
  {
    return val->getInt();
  }

  if (val->getType() == Object::ParamType::STRING)
  {
    return atoi(val->getString().c_str());
  }

  if (val->getType() == Object::ParamType::LISTOBJ)
  {
    Object_list_ptr list = val->getLO();
    if (list->size() == 1)
    {
      return castToInteger((*(list->begin())));
    }
  }

  if (val->getType() == Object::ParamType::BOOL)
  {
    if (val->getBool())
    {
      return 1;
    }
    else
    {
      return 0;
    }
  }

  if (val->getType() == Object::ParamType::DOUBLE)
  {
    // return ((double) val).intValue();
    return val->getDouble();
  }

  throw new FastsqlException(make_string_ptr("cast error"));
}

// @SuppressWarnings("rawtypes")
long SQLEvalVisitorUtils::castToLong(Object_ptr val)
{
  if (val == nullptr)
  {
    return NULL;
  }

  if (val->getType() == Object::ParamType::LONG)
  {
    return val->getLong();
  }

  if (val->getType() == Object::ParamType::STRING)
  {
    return atol(val->getString().c_str());
  }

  if (val->getType() == Object::ParamType::LISTOBJ)
  {
    Object_list_ptr list = val->getLO();
    if (list->size() == 1)
    {
      return castToLong((*(list->begin())));
    }
  }

  if (val->getType() == Object::ParamType::BOOL)
  {
    if (val->getBool())
    {
      return 1L;
    }
    else
    {
      return 0L;
    }
  }

  // return ((double) val).longValue();
  return val->getDouble();
}

float SQLEvalVisitorUtils::castToFloat(Object_ptr val)
{
  if (val == nullptr || val == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return NULL;
  }

  if (val->getType() == Object::ParamType::FLOAT)
  {
    return val->getFloat();
  }

  // return ((double) val).floatValue();
  return val->getDouble();
}

double SQLEvalVisitorUtils::castToDouble(Object_ptr val)
{
  if (val == nullptr || val == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return NULL;
  }

  if (val->getType() == Object::ParamType::DOUBLE)
  {
    return val->getDouble();
  }

  // return ((double) val).doubleValue();
  return val->getDouble();
}

long long SQLEvalVisitorUtils::castToBigInteger(Object_ptr val)
{
  if (val == nullptr)
  {
    return NULL;
  }

  if (val->getType() == Object::ParamType::LONGLONG)
  {
    return val->getLongLong();
  }

  if (val->getType() == Object::ParamType::STRING)
  {
    return std::stoll(val->getString());
  }

  // return long long.valueOf(((double) val).longValue());
  return val->getDouble();
}

double SQLEvalVisitorUtils::castToNumber(string_ptr val)
{
  if (val == nullptr)
  {
    return NULL;
  }

  // try {
  //     return Byte.parseByte(val);
  // } catch (NumberFormatException e) {
  // }

  // try {
  //     return Short.parseShort(val);
  // } catch (NumberFormatException e) {
  // }

  // try {
  //     return Integer.parseInt(val);
  // } catch (NumberFormatException e) {
  // }

  // try {
  //     return long.parseLong(val);
  // } catch (NumberFormatException e) {
  // }

  // try {
  //     return float.parseFloat(val);
  // } catch (NumberFormatException e) {
  // }

  // try {
  //     return double.parseDouble(val);
  // } catch (NumberFormatException e) {
  // }

  // try {
  //     return new long long(val);
  // } catch (NumberFormatException e) {
  // }

  // try {
  //     return new BigDecimal(val);
  // } catch (NumberFormatException e) {
  //     return 0;
  // }
  return std::stold(val->c_str());
}

time_t SQLEvalVisitorUtils::castToDate(Object_ptr val)
{
  if (val == nullptr)
  {
    return NULL;
  }

  if (val->getType() == Object::ParamType::LONG)
  {
    return (time_t)val->getLong();
  }

  if (val->getType() == Object::ParamType::DOUBLE)
  {
    return time_t(val->getDouble());
  }

  if (val->getType() == Object::ParamType::STRING)
  {
    return castToDate(make_string_ptr(val->getString()));
  }

  throw new FastsqlException(make_string_ptr("can cast to date"));
}

time_t SQLEvalVisitorUtils::castToDate(string_ptr text)
{
  if (text == nullptr || text->length() == 0)
  {
    return NULL;
  }

  std::string format;

  // if (text->length() == "yyyy-MM-dd".length()) {
  if (text->length() == 10)
  {
    format = "yyyy-MM-dd";
  }
  else
  {
    format = "yyyy-MM-dd HH:mm:ss";
  }

  // try {
  //     return new SimpleDateFormat(format).parse(text);
  // } catch (ParseException e) {
  //     throw new FastsqlException("rowFormat : " + format + ", value : " + text, e);
  // }
  return TimeUtils::convertTimeStr2TimeStamp(format, text->c_str());
}

double SQLEvalVisitorUtils::castToDecimal(Object_ptr val)
{
  if (val == nullptr)
  {
    return NULL;
  }

  // if (val instanceof BigDecimal) {
  //     return (BigDecimal) val;
  // }

  if (val->getType() == Object::ParamType::STRING)
  {
    return std::stold(val->getString());
  }

  if (val->getType() == Object::ParamType::FLOAT)
  {
    // return new BigDecimal((float) val);
    return val->getFloat();
  }

  if (val->getType() == Object::ParamType::DOUBLE)
  {
    // return new BigDecimal((double) val);
    return val->getDouble();
  }

  return val->getDouble();
  // return BigDecimal.valueOf(((double) val).longValue());
}

Object_ptr SQLEvalVisitorUtils::rightShift(Object_ptr a, Object_ptr b)
{
  if (a == nullptr || b == nullptr)
  {
    return NULL;
  }

  if (a->getType() == Object::ParamType::LONG || b->getType() == Object::ParamType::LONG)
  {
    return Object_ptr(new Object(castToLong(a) >> castToLong(b)));
  }

  return Object_ptr(new Object(castToInteger(a) >> castToInteger(b)));
}

Object_ptr SQLEvalVisitorUtils::bitAnd(Object_ptr a, Object_ptr b)
{
  if (a == nullptr || b == nullptr)
  {
    return nullptr;
  }

  if (a == SQLEvalVisitor::EVAL_VALUE_NULL || b == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return nullptr;
  }

  if (a->getType() == Object::ParamType::STRING)
  {
    a = Object_ptr(new Object(castToNumber(make_string_ptr(a->getString()))));
  }

  if (b->getType() == Object::ParamType::STRING)
  {
    b = Object_ptr(new Object(castToNumber(make_string_ptr(b->getString()))));
  }

  if (a->getType() == Object::ParamType::LONG || b->getType() == Object::ParamType::LONG)
  {
    return Object_ptr(new Object(castToLong(a) & castToLong(b)));
  }

  return Object_ptr(new Object(castToInteger(a) & castToInteger(b)));
}

Object_ptr SQLEvalVisitorUtils::bitOr(Object_ptr a, Object_ptr b)
{
  if (a == nullptr || b == nullptr)
  {
    return nullptr;
  }

  if (a == SQLEvalVisitor::EVAL_VALUE_NULL || b == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return nullptr;
  }

  if (a->getType() == Object::ParamType::STRING)
  {
    a = Object_ptr(new Object(castToNumber(make_string_ptr(a->getString()))));
  }

  if (b->getType() == Object::ParamType::STRING)
  {
    b = Object_ptr(new Object(castToNumber(make_string_ptr(b->getString()))));
  }

  if (a->getType() == Object::ParamType::LONG || b->getType() == Object::ParamType::LONG)
  {
    return Object_ptr(new Object(castToLong(a) | castToLong(b)));
  }

  return Object_ptr(new Object(castToInteger(a) | castToInteger(b)));
}

Object_ptr SQLEvalVisitorUtils::div(Object_ptr a, Object_ptr b)
{
  if (a == nullptr || b == nullptr)
  {
    return nullptr;
  }

  if (a == SQLEvalVisitor::EVAL_VALUE_NULL || b == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return nullptr;
  }

  if (a->getType() == Object::ParamType::STRING)
  {
    a = Object_ptr(new Object(castToNumber(make_string_ptr(a->getString()))));
  }

  if (b->getType() == Object::ParamType::STRING)
  {
    b = Object_ptr(new Object(castToNumber(make_string_ptr(b->getString()))));
  }

  // if (a instanceof BigDecimal || b instanceof BigDecimal) {
  //     BigDecimal decimalA = castToDecimal(a);
  //     BigDecimal decimalB = castToDecimal(b);
  //     if (decimalB.scale() < decimalA.scale()) {
  //         decimalB = decimalB.setScale(decimalA.scale());
  //     }
  //     try {
  //         return decimalA.divide(decimalB);
  //     } catch (ArithmeticException ex) {
  //         return decimalA.divide(decimalB, BigDecimal.ROUND_HALF_UP);
  //     }
  // }

  if (a->getType() == Object::ParamType::DOUBLE || b->getType() == Object::ParamType::DOUBLE)
  {
    double doubleA = castToDouble(a);
    double doubleB = castToDouble(b);
    // if (doubleA == nullptr || doubleB == nullptr) {
    //     return nullptr;
    // }
    return Object_ptr(new Object(doubleA / doubleB));
  }

  if (a->getType() == Object::ParamType::FLOAT || b->getType() == Object::ParamType::FLOAT)
  {
    float floatA = castToFloat(a);
    float floatB = castToFloat(b);
    // if (floatA == nullptr || floatB == nullptr) {
    //     return nullptr;
    // }
    return Object_ptr(new Object(floatA / floatB));
  }

  if (a->getType() == Object::ParamType::LONGLONG || b->getType() == Object::ParamType::LONGLONG)
  {
    return Object_ptr(new Object(castToBigInteger(a) / (castToBigInteger(b))));
  }

  if (a->getType() == Object::ParamType::LONG || b->getType() == Object::ParamType::LONG)
  {
    long longA = castToLong(a);
    long longB = castToLong(b);
    if (longB == 0)
    {
      if (longA > 0)
      {
        return Object_ptr(new Object(DBL_MAX));
      }
      else if (longA < 0)
      {
        return Object_ptr(new Object(DBL_MIN));
      }
      else
      {
        return nullptr;
      }
    }
    return Object_ptr(new Object(longA / longB));
  }

  if (a->getType() == Object::ParamType::INT || b->getType() == Object::ParamType::INT)
  {
    int intA = castToInteger(a);
    int intB = castToInteger(b);
    if (intB == 0)
    {
      if (intA > 0)
      {
        return Object_ptr(new Object(DBL_MAX));
      }
      else if (intA < 0)
      {
        return Object_ptr(new Object(DBL_MIN));
      }
      else
      {
        return nullptr;
      }
    }
    return Object_ptr(new Object(intA / intB));
  }

  if (a->getType() == Object::ParamType::SHORT || b->getType() == Object::ParamType::SHORT)
  {
    return Object_ptr(new Object(castToShort(a) / castToShort(b)));
  }

  if (a->getType() == Object::ParamType::CHAR || b->getType() == Object::ParamType::CHAR)
  {
    return Object_ptr(new Object(castToByte(a) / castToByte(b)));
  }

  std::string tmp = a->getClass()->c_str();
  tmp += " and ";
  tmp += b->getClass()->c_str();
  tmp += " not supported.";
  throw new IllegalArgumentException(make_string_ptr(tmp));
}

bool SQLEvalVisitorUtils::gt(Object_ptr a, Object_ptr b)
{
  if (a == nullptr || a == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return false;
  }

  if (b == nullptr || b == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return true;
  }

  if (a->getType() == Object::ParamType::STRING || b->getType() == Object::ParamType::STRING)
  {
    return (*castToString(a)).compare(*castToString(b)) > 0;
  }

  // if (a instanceof BigDecimal || b instanceof BigDecimal) {
  //     return castToDecimal(a).compareTo(castToDecimal(b)) > 0;
  // }

  if (a->getType() == Object::ParamType::LONGLONG || b->getType() == Object::ParamType::LONGLONG)
  {
    return castToBigInteger(a) - (castToBigInteger(b)) > 0;
  }

  if (a->getType() == Object::ParamType::LONG || b->getType() == Object::ParamType::LONG)
  {
    return castToLong(a) > castToLong(b);
  }

  if (a->getType() == Object::ParamType::INT || b->getType() == Object::ParamType::INT)
  {
    return castToInteger(a) > castToInteger(b);
  }

  if (a->getType() == Object::ParamType::SHORT || b->getType() == Object::ParamType::SHORT)
  {
    return castToShort(a) > castToShort(b);
  }

  if (a->getType() == Object::ParamType::CHAR || b->getType() == Object::ParamType::CHAR)
  {
    return castToByte(a) > castToByte(b);
  }

  // if (a instanceof time_t || b instanceof time_t) {
  //     time_t d1 = castToDate(a);
  //     time_t d2 = castToDate(b);

  //     if (d1 == d2) {
  //         return false;
  //     }

  //     if (d1 == nullptr) {
  //         return false;
  //     }

  //     if (d2 == nullptr) {
  //         return true;
  //     }

  //     return d1.compareTo(d2) > 0;
  // }

  std::string tmp = a->getClass()->c_str();
  tmp += " and ";
  tmp += b->getClass()->c_str();
  tmp += " not supported.";
  throw new IllegalArgumentException(make_string_ptr(tmp));
}

bool SQLEvalVisitorUtils::gteq(Object_ptr a, Object_ptr b)
{
  if (eq(a, b))
  {
    return true;
  }

  return gt(a, b);
}

bool SQLEvalVisitorUtils::lt(Object_ptr a, Object_ptr b)
{
  if (a == nullptr)
  {
    return true;
  }

  if (b == nullptr)
  {
    return false;
  }

  if (a->getType() == Object::ParamType::STRING || b->getType() == Object::ParamType::STRING)
  {
    return (*castToString(a)).compare(*castToString(b)) < 0;
  }

  // if (a instanceof BigDecimal || b instanceof BigDecimal) {
  //     return castToDecimal(a).compareTo(castToDecimal(b)) < 0;
  // }

  if (a->getType() == Object::ParamType::LONGLONG || b->getType() == Object::ParamType::LONGLONG)
  {
    return castToBigInteger(a) - (castToBigInteger(b)) < 0;
  }

  if (a->getType() == Object::ParamType::LONG || b->getType() == Object::ParamType::LONG)
  {
    return castToLong(a) < castToLong(b);
  }

  if (a->getType() == Object::ParamType::INT || b->getType() == Object::ParamType::INT)
  {
    int intA = castToInteger(a);
    int intB = castToInteger(b);
    return intA < intB;
  }

  if (a->getType() == Object::ParamType::SHORT || b->getType() == Object::ParamType::SHORT)
  {
    return castToShort(a) < castToShort(b);
  }

  if (a->getType() == Object::ParamType::CHAR || b->getType() == Object::ParamType::CHAR)
  {
    return castToByte(a) < castToByte(b);
  }

  // if (a instanceof time_t || b instanceof time_t) {
  //     time_t d1 = castToDate(a);
  //     time_t d2 = castToDate(b);

  //     if (d1 == d2) {
  //         return false;
  //     }

  //     if (d1 == nullptr) {
  //         return true;
  //     }

  //     if (d2 == nullptr) {
  //         return false;
  //     }

  //     return d1.compareTo(d2) < 0;
  // }

  std::string tmp = a->getClass()->c_str();
  tmp += " and ";
  tmp += b->getClass()->c_str();
  tmp += " not supported.";
  throw new IllegalArgumentException(make_string_ptr(tmp));
}

bool SQLEvalVisitorUtils::lteq(Object_ptr a, Object_ptr b)
{
  if (eq(a, b))
  {
    return true;
  }

  return lt(a, b);
}

bool SQLEvalVisitorUtils::eq(Object_ptr a, Object_ptr b)
{
  if (a == b)
  {
    return true;
  }

  if (a == nullptr || b == nullptr)
  {
    return false;
  }

  if (a == SQLEvalVisitor::EVAL_VALUE_NULL || b == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return false;
  }

  if (a->equals(b))
  {
    return true;
  }

  if (a->getType() == Object::ParamType::STRING || b->getType() == Object::ParamType::STRING)
  {
    return castToString(a)->c_str() == (castToString(b))->c_str();
  }

  // if (a instanceof BigDecimal || b instanceof BigDecimal) {
  //     return castToDecimal(a).compareTo(castToDecimal(b)) == 0;
  // }

  if (a->getType() == Object::ParamType::LONGLONG || b->getType() == Object::ParamType::LONGLONG)
  {
    return castToBigInteger(a) - (castToBigInteger(b)) == 0;
  }

  if (a->getType() == Object::ParamType::LONG || b->getType() == Object::ParamType::LONG)
  {
    return castToLong(a) == (castToLong(b));
  }

  if (a->getType() == Object::ParamType::INT || b->getType() == Object::ParamType::INT)
  {
    int inta = castToInteger(a);
    int intb = castToInteger(b);
    // if (inta == nullptr || intb == nullptr) {
    //     return false;
    // }
    return inta == (intb);
  }

  if (a->getType() == Object::ParamType::SHORT || b->getType() == Object::ParamType::SHORT)
  {
    return castToShort(a) == (castToShort(b));
  }

  if (a->getType() == Object::ParamType::BOOL || b->getType() == Object::ParamType::BOOL)
  {
    return castToBoolean(a) == castToBoolean(b);
  }

  if (a->getType() == Object::ParamType::CHAR || b->getType() == Object::ParamType::CHAR)
  {
    return castToByte(a) == (castToByte(b));
  }

  // if (a instanceof time_t || b instanceof time_t) {
  //     time_t d1 = castToDate(a);
  //     time_t d2 = castToDate(b);

  //     if (d1 == d2) {
  //         return true;
  //     }

  //     if (d1 == nullptr || d2 == nullptr) {
  //         return false;
  //     }

  //     return d1.equals(d2);
  // }

  std::string tmp = a->getClass()->c_str();
  tmp += " and ";
  tmp += b->getClass()->c_str();
  tmp += " not supported.";
  throw new IllegalArgumentException(make_string_ptr(tmp));
}

Object_ptr SQLEvalVisitorUtils::add(Object_ptr a, Object_ptr b)
{
  if (a == nullptr)
  {
    return b;
  }

  if (b == nullptr)
  {
    return a;
  }

  if (a == SQLEvalVisitor::EVAL_VALUE_NULL || b == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return SQLEvalVisitor::EVAL_VALUE_NULL;
  }

  if (a->getType() == Object::ParamType::STRING && !(b->getType() == Object::ParamType::STRING))
  {
    a = Object_ptr(new Object(castToNumber(make_string_ptr(a->getString()))));
  }

  if (b->getType() == Object::ParamType::STRING && !(a->getType() == Object::ParamType::STRING))
  {
    b = Object_ptr(new Object(castToNumber(make_string_ptr(b->getString()))));
  }

  // if (a instanceof BigDecimal || b instanceof BigDecimal) {
  //     return castToDecimal(a).add(castToDecimal(b));
  // }

  if (a->getType() == Object::ParamType::LONGLONG || b->getType() == Object::ParamType::LONGLONG)
  {
    return Object_ptr(new Object(castToBigInteger(a) + castToBigInteger(b)));
  }

  if (a->getType() == Object::ParamType::DOUBLE || b->getType() == Object::ParamType::DOUBLE)
  {
    return Object_ptr(new Object(castToDouble(a) + castToDouble(b)));
  }

  if (a->getType() == Object::ParamType::FLOAT || b->getType() == Object::ParamType::FLOAT)
  {
    return Object_ptr(new Object(castToFloat(a) + castToFloat(b)));
  }

  if (a->getType() == Object::ParamType::LONG || b->getType() == Object::ParamType::LONG)
  {
    return Object_ptr(new Object(castToLong(a) + castToLong(b)));
  }

  if (a->getType() == Object::ParamType::INT || b->getType() == Object::ParamType::INT)
  {
    return Object_ptr(new Object(castToInteger(a) + castToInteger(b)));
  }

  if (a->getType() == Object::ParamType::SHORT || b->getType() == Object::ParamType::SHORT)
  {
    return Object_ptr(new Object(castToShort(a) + castToShort(b)));
  }

  if (a->getType() == Object::ParamType::BOOL || b->getType() == Object::ParamType::BOOL)
  {
    int aI = 0, bI = 0;
    if (castToBoolean(a))
    {
      aI = 1;
    }
    if (castToBoolean(b))
    {
      bI = 1;
    }
    return Object_ptr(new Object(aI + bI));
  }

  if (a->getType() == Object::ParamType::CHAR || b->getType() == Object::ParamType::CHAR)
  {
    return Object_ptr(new Object(castToByte(a) + castToByte(b)));
  }

  if (a->getType() == Object::ParamType::STRING && b->getType() == Object::ParamType::STRING)
  {
    std::string tmp = castToString(a)->c_str();
    tmp += castToString(b)->c_str();
    return Object_ptr(new Object(tmp));
  }

  std::string tmp = a->getClass()->c_str();
  tmp += " and ";
  tmp += b->getClass()->c_str();
  tmp += " not supported.";
  throw new IllegalArgumentException(make_string_ptr(tmp));
}

Object_ptr SQLEvalVisitorUtils::sub(Object_ptr a, Object_ptr b)
{
  if (a == nullptr)
  {
    return nullptr;
  }

  if (b == nullptr)
  {
    return a;
  }

  if (a == SQLEvalVisitor::EVAL_VALUE_NULL || b == SQLEvalVisitor::EVAL_VALUE_NULL)
  {
    return SQLEvalVisitor::EVAL_VALUE_NULL;
  }

  // if (a instanceof time_t || b instanceof time_t) {
  //     return SQLEvalVisitor* .EVAL_ERROR;
  // }

  if (a->getType() == Object::ParamType::STRING)
  {
    a = Object_ptr(new Object(castToNumber(make_string_ptr(a->getString()))));
  }

  if (b->getType() == Object::ParamType::STRING)
  {
    b = Object_ptr(new Object(castToNumber(make_string_ptr(b->getString()))));
  }

  // if (a instanceof BigDecimal || b instanceof BigDecimal) {
  //     return castToDecimal(a).subtract(castToDecimal(b));
  // }

  if (a->getType() == Object::ParamType::LONGLONG || b->getType() == Object::ParamType::LONGLONG)
  {
    return Object_ptr(new Object(castToBigInteger(a) - castToBigInteger(b)));
  }

  if (a->getType() == Object::ParamType::DOUBLE || b->getType() == Object::ParamType::DOUBLE)
  {
    return Object_ptr(new Object(castToDouble(a) - castToDouble(b)));
  }

  if (a->getType() == Object::ParamType::FLOAT || b->getType() == Object::ParamType::FLOAT)
  {
    return Object_ptr(new Object(castToFloat(a) - castToFloat(b)));
  }

  if (a->getType() == Object::ParamType::LONG || b->getType() == Object::ParamType::LONG)
  {
    return Object_ptr(new Object(castToLong(a) - castToLong(b)));
  }

  if (a->getType() == Object::ParamType::INT || b->getType() == Object::ParamType::INT)
  {
    return Object_ptr(new Object(castToInteger(a) - castToInteger(b)));
  }

  if (a->getType() == Object::ParamType::SHORT || b->getType() == Object::ParamType::SHORT)
  {
    return Object_ptr(new Object(castToShort(a) - castToShort(b)));
  }

  if (a->getType() == Object::ParamType::BOOL || b->getType() == Object::ParamType::BOOL)
  {
    int aI = 0, bI = 0;
    if (castToBoolean(a))
    {
      aI = 1;
    }
    if (castToBoolean(b))
    {
      bI = 1;
    }
    return Object_ptr(new Object(aI - bI));
  }

  if (a->getType() == Object::ParamType::CHAR || b->getType() == Object::ParamType::CHAR)
  {
    return Object_ptr(new Object(castToByte(a) - castToByte(b)));
  }

  // return SQLEvalVisitor* .EVAL_ERROR;
  std::string tmp = a->getClass()->c_str();
  tmp += " and ";
  tmp += b->getClass()->c_str();
  tmp += " not supported.";
  throw new IllegalArgumentException(make_string_ptr(tmp));
}

Object_ptr SQLEvalVisitorUtils::multi(Object_ptr a, Object_ptr b)
{
  if (a == nullptr || b == nullptr)
  {
    return nullptr;
  }

  if (a->getType() == Object::ParamType::STRING)
  {
    a = Object_ptr(new Object(castToNumber(make_string_ptr(a->getString()))));
  }

  if (b->getType() == Object::ParamType::STRING)
  {
    b = Object_ptr(new Object(castToNumber(make_string_ptr(b->getString()))));
  }

  // if (a instanceof BigDecimal || b instanceof BigDecimal) {
  //     return castToDecimal(a).multiply(castToDecimal(b));
  // }

  if (a->getType() == Object::ParamType::LONGLONG || b->getType() == Object::ParamType::LONGLONG)
  {
    return Object_ptr(new Object(castToBigInteger(a) * castToBigInteger(b)));
  }

  if (a->getType() == Object::ParamType::DOUBLE || b->getType() == Object::ParamType::DOUBLE)
  {
    return Object_ptr(new Object(castToDouble(a) * castToDouble(b)));
  }

  if (a->getType() == Object::ParamType::FLOAT || b->getType() == Object::ParamType::FLOAT)
  {
    return Object_ptr(new Object(castToFloat(a) * castToFloat(b)));
  }

  if (a->getType() == Object::ParamType::LONG || b->getType() == Object::ParamType::LONG)
  {
    return Object_ptr(new Object(castToLong(a) * castToLong(b)));
  }

  if (a->getType() == Object::ParamType::INT || b->getType() == Object::ParamType::INT)
  {
    return Object_ptr(new Object(castToInteger(a) * castToInteger(b)));
  }

  if (a->getType() == Object::ParamType::SHORT || b->getType() == Object::ParamType::SHORT)
  {
    short shortA = castToShort(a);
    short shortB = castToShort(b);

    // if (shortA == nullptr || shortB == nullptr) {
    //     return nullptr;
    // }

    return Object_ptr(new Object(shortA * shortB));
  }

  if (a->getType() == Object::ParamType::CHAR || b->getType() == Object::ParamType::CHAR)
  {
    return Object_ptr(new Object(castToByte(a) * castToByte(b)));
  }

  std::string tmp = a->getClass()->c_str();
  tmp += " and ";
  tmp += b->getClass()->c_str();
  tmp += " not supported.";
  throw new IllegalArgumentException(make_string_ptr(tmp));
}

bool SQLEvalVisitorUtils::like(string_ptr input, string_ptr pattern)
{
  if (pattern == nullptr)
  {
    throw new IllegalArgumentException(make_string_ptr("pattern is nullptr"));
  }

  std::stringstream regexprBuilder;

  int STAT_NOTSET = 0;
  int STAT_RANGE = 1;
  int STAT_LITERAL = 2;

  int stat = STAT_NOTSET;

  int blockStart = -1;
  for (int i = 0; i < pattern->length(); ++i)
  {
    char ch = pattern->at(i);

    if (stat == STAT_LITERAL //
        && (ch == '%' || ch == '_' || ch == '['))
    {
      std::string block = pattern->substr(blockStart, i);
      regexprBuilder << "\\Q";
      regexprBuilder << block;
      regexprBuilder << "\\E";
      blockStart = -1;
      stat = STAT_NOTSET;
    }

    if (ch == '%')
    {
      regexprBuilder << ".*";
    }
    else if (ch == '_')
    {
      regexprBuilder << '.';
    }
    else if (ch == '[')
    {
      if (stat == STAT_RANGE)
      {
        std::string tmp = "illegal pattern : ";
        tmp += pattern->c_str();
        throw new IllegalArgumentException(make_string_ptr(tmp));
      }
      stat = STAT_RANGE;
      blockStart = i;
    }
    else if (ch == ']')
    {
      if (stat != STAT_RANGE)
      {
        std::string tmp = "illegal pattern : ";
        tmp += pattern->c_str();
        throw new IllegalArgumentException(make_string_ptr(tmp));
      }
      std::string block = pattern->substr(blockStart, i + 1);
      regexprBuilder << block;

      blockStart = -1;
    }
    else
    {
      if (stat == STAT_NOTSET)
      {
        stat = STAT_LITERAL;
        blockStart = i;
      }

      if (stat == STAT_LITERAL && i == pattern->length() - 1)
      {
        std::string block = pattern->substr(blockStart, i + 1);
        regexprBuilder << "\\Q";
        regexprBuilder << block;
        regexprBuilder << "\\E";
      }
    }
  }
  if ("%" == pattern->c_str() || "%%" == pattern->c_str())
  {
    return true;
  }

  std::string regexpr = regexprBuilder.str();
  // return Pattern.matches(regexpr, input);
  std::regex reg(regexpr.c_str());
  return std::regex_match(input->c_str(), reg);
}

bool SQLEvalVisitorUtils::visit(SQLEvalVisitor *visitor, SQLIdentifierExpr_ptr x)
{
  x->putAttribute(SQLEvalVisitor::EVAL_EXPR->c_str(), x);
  return false;
}
